package com.atguigu.gmall.publisher.service.impl;

import com.atguigu.gmall.publisher.bean.DetailStats;
import com.atguigu.gmall.publisher.bean.NameValue;
import com.atguigu.gmall.publisher.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.ParsedSum;
import org.elasticsearch.search.aggregations.metrics.SumAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class OrderServiceImpl  implements OrderService {

    public static final String  indexNamePrefix="gmall0722_order_wide_";

    @Autowired
    RestHighLevelClient restHighLevelClient;

    @Override
    public List<NameValue> statsByItem(String itemName, String date, String type) {
        List nameValueList=new ArrayList();
        String indexName =indexNamePrefix+date;
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //1 查询
        searchSourceBuilder.query(new MatchQueryBuilder("sku_name",itemName).operator(Operator.AND));

        //2 去除明细结果
        searchSourceBuilder.size(0);
        //3 聚合
        String groupField = getGroupFieldByType(type);
        // 3.1 分组
        TermsAggregationBuilder groupByAgg = AggregationBuilders.terms("groupby_" + type).field(groupField).size(100);
        //3.2 聚合
        SumAggregationBuilder sumAgg = AggregationBuilders.sum("sum_amount").field("split_total_amount");
        //3.3  套娃
        groupByAgg.subAggregation(sumAgg);

        searchSourceBuilder.aggregation(groupByAgg);

        SearchRequest searchRequest = new SearchRequest(indexName).source(searchSourceBuilder);

        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            Aggregations aggregations = searchResponse.getAggregations();
            ParsedStringTerms groupbyAggRs = aggregations.get("groupby_" + type);
            List<? extends Terms.Bucket> buckets = groupbyAggRs.getBuckets(); // 先提出各个分组的集合
            for (Terms.Bucket bucket : buckets) {
                String key = bucket.getKeyAsString();
                //从每个分组中提取聚合值
                ParsedSum sumAggRs = bucket.getAggregations().get("sum_amount");
                double sumAmount = sumAggRs.getValue();
                //组合成新对象  存入结果列表
                nameValueList.add(new NameValue(key, new BigDecimal(sumAmount)));
            }
            return trimResult(nameValueList);

        }catch (ElasticsearchStatusException ese){
            if( ese.status()== RestStatus.NOT_FOUND){
                log.warn("不存在该索引:"+ese.getIndex().getName());
                return  new ArrayList<>();
            }else{
                throw  new RuntimeException("es 查询失败");
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw  new RuntimeException("es 查询失败");
        }
    }



    public  List<NameValue>  trimResult(List<NameValue> nameValueList){
        for (NameValue nameValue : nameValueList) {
            if(nameValue.getName().equals("F")){
                nameValue.setName("女");
            }else if(nameValue.getName().equals("M")){
                nameValue.setName("男");
            }else{
                nameValue.setName("未知");
            }
        }
        return nameValueList;
    }


    private String getGroupFieldByType(String type){
            if( "gender".equals(type)){
                return "user_gender";
            }else{
                throw new RuntimeException("不存在的类型 ");
            }
    }





    @Override
    public DetailStats detailByItem(String itemName, String date, Integer pageNo, Integer pageSize) {
        String indexName =indexNamePrefix+date;
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //字段
        String[] fields = {"create_time", "sku_name", "order_price", "province_name", "sku_name", "sku_num", "total_amount", "user_age", "user_gender"};
        searchSourceBuilder.fetchSource(fields,null);
        //查询
        searchSourceBuilder.query(new MatchQueryBuilder("sku_name",itemName).operator(Operator.AND));
        //高亮
        searchSourceBuilder.highlighter(new HighlightBuilder().field("sku_name"));
        //分页
        searchSourceBuilder.from((pageNo-1)*pageSize );
        searchSourceBuilder.size(pageSize);

        SearchRequest searchRequest = new SearchRequest(indexName).source(searchSourceBuilder);

        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            long total = searchResponse.getHits().getTotalHits().value;
            List<Map> detailList = new ArrayList<>();
            SearchHit[] hits = searchResponse.getHits().getHits();
            for (SearchHit hit : hits) {
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                //提取高亮值
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField highlightField = highlightFields.get("sku_name");
                Text text = highlightField.getFragments()[0];
                String skuNameHL = text.string();
                //覆盖原值
                sourceAsMap.put("sku_name",skuNameHL);

                detailList.add(sourceAsMap);
            }
            return new DetailStats(total,detailList);
        }catch (ElasticsearchStatusException ese){
            if( ese.status()== RestStatus.NOT_FOUND){
                log.warn("不存在该索引:"+ese.getIndex().getName());
                return  new DetailStats(0L,new ArrayList<>());
            }else{
                throw  new RuntimeException("es 查询失败");
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw  new RuntimeException("es 查询失败");
        }

    }

}
